package cn.tedu.mall.seckill.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.pojo.domain.CsmallAuthenticationInfo;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.order.service.IOmsOrderService;
import cn.tedu.mall.pojo.order.dto.OrderAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.order.vo.OrderAddVO;
import cn.tedu.mall.pojo.seckill.dto.SeckillOrderAddDTO;
import cn.tedu.mall.pojo.seckill.dto.SeckillOrderItemAddDTO;
import cn.tedu.mall.pojo.seckill.model.Success;
import cn.tedu.mall.pojo.seckill.vo.SeckillCommitVO;
import cn.tedu.mall.product.service.order.IForOrderSkuService;
import cn.tedu.mall.seckill.config.RabbitMqComponentConfiguration;
import cn.tedu.mall.seckill.service.ISeckillService;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author BJ
 * @date 2022/11/11 16:05
 */
@Service
@Slf4j
public class SeckillServiceImpl implements ISeckillService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @DubboReference
    private IOmsOrderService orderService;
    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 执行订单秒杀
     * 1.判断用户是否重复购买sku商品、sku商品库存是否不够
     * 2.将秒杀订单 -> 普通订单，dubbo远程调用普通订单的生成方法
     * 3.使用RabbitMQ消息队列将秒杀成功的订单信息保存到Success表中
     * 4.秒杀订单消息返回
     * @param seckillOrderAddDTO
     * @return
     */
    // 秒杀订单的生成
    @Override
    public SeckillCommitVO commitSeckill(SeckillOrderAddDTO seckillOrderAddDTO) {
        // 1.【通过userId和skuId判断用户是否重复购买商品】
        Long skuId = seckillOrderAddDTO.getSeckillOrderItemAddDTO().getSkuId();
        Long spuId = seckillOrderAddDTO.getSpuId();
        String reseckillCheckKey = SeckillCacheUtils.getReseckillCheckKey(skuId, spuId);
        // increment() :数量增加1  以下skuCount变量表示数量增加后的值
        // 用户第一次购买应该是 从0->1，数量为1，数量大于1表示已经重复购买了
        // increment()将绑定键下存储为字符串值的整数值加1
        Long skuCount = stringRedisTemplate.boundValueOps(reseckillCheckKey).increment();
        if (skuCount > 1) {
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,
                    "不可重复购买此商品！");
        }
        String stockKey = SeckillCacheUtils.getStockKey(skuId);
        // decrement():数量减1  stockCount表示减1后的值，如果小于0，表示库存不足
        Long stockCount = stringRedisTemplate.boundValueOps(stockKey).decrement();
        if (stockCount < 0){
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,
                    "对不起,您想要购买的商品已经售罄！");
        }
        // 2.【秒杀订单 -> 普通订单】
        OrderAddDTO orderAddDTO = converSeckillOrderAddDTO(seckillOrderAddDTO);
        // userId只能从后端拿取，前端不可能存在
        orderAddDTO.setUserId(getUserId());
        // 生成订单
        OrderAddVO orderAddVO = orderService.addOrder(orderAddDTO);
        // 3.【使用Rabbitmq完成下单成功后保存到Success表中】
        Success success = new Success();
        BeanUtils.copyProperties(seckillOrderAddDTO.getSeckillOrderItemAddDTO(),success);
        success.setOrderSn(orderAddVO.getSn());
        success.setUserId(getUserId());
        success.setSeckillPrice(seckillOrderAddDTO.getSeckillOrderItemAddDTO().getPrice());
        // 消息队列发消息
        rabbitTemplate.convertAndSend(
                RabbitMqComponentConfiguration.SECKILL_EX,
                RabbitMqComponentConfiguration.SECKILL_RK,
                success);

        SeckillCommitVO commitVO = new SeckillCommitVO();
        BeanUtils.copyProperties(orderAddVO,commitVO);
        return commitVO;
    }

    private OrderAddDTO converSeckillOrderAddDTO(SeckillOrderAddDTO seckillOrderAddDTO) {
        // 订单属性赋值
        OrderAddDTO orderAddDTO = new OrderAddDTO();
        BeanUtils.copyProperties(seckillOrderAddDTO,orderAddDTO);

        // 单独将订单项属性赋值
        OrderItemAddDTO orderItemAddDTO = new OrderItemAddDTO();
        BeanUtils.copyProperties(seckillOrderAddDTO.getSeckillOrderItemAddDTO(),orderItemAddDTO);

        List<OrderItemAddDTO> orderItemAddDTOS = new ArrayList<>();
        orderItemAddDTOS.add(orderItemAddDTO);

        orderAddDTO.setOrderItems(orderItemAddDTOS);
        return orderAddDTO;
    }

    public CsmallAuthenticationInfo getUserInfo(){
        UsernamePasswordAuthenticationToken authenticationToken =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext();
        if (authenticationToken == null){
            throw new CoolSharkServiceException(ResponseCode.NOT_FOUND,"登录信息错误！");
        }
        CsmallAuthenticationInfo csmallAuthenticationInfo =
                (CsmallAuthenticationInfo) authenticationToken.getCredentials();

        return csmallAuthenticationInfo;
    }
    public Long getUserId(){
        return getUserInfo().getId();
    }
}
